/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *
 * http://www.gnu.org/copyleft/gpl.html
 */
package net.sf.l2j.gameserver.handler;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Collection;
import java.util.concurrent.ScheduledFuture;

import javolution.text.TextBuilder;
import javolution.util.FastMap;
import net.sf.l2j.database.L2DatabaseFactory;
import net.sf.l2j.gameserver.Announcements;
import net.sf.l2j.gameserver.ThreadPoolManager;
import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
import net.sf.l2j.gameserver.network.serverpackets.NpcHtmlMessage;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Auto Announcment Handler Automatically send announcment at a set time
 * interval.
 */
public class AutoAnnouncementHandler {
	protected static Log _log = LogFactory.getLog(AutoAnnouncementHandler.class
			.getName());
	private static AutoAnnouncementHandler _instance;
	private static final long DEFAULT_ANNOUNCEMENT_DELAY = 180000; // 3 mins by
																	// default
	protected FastMap<Integer, AutoAnnouncementInstance> _registeredAnnouncements;

	protected AutoAnnouncementHandler() {
		_registeredAnnouncements = new FastMap<Integer, AutoAnnouncementInstance>();
		restoreAnnouncementData();
	}

	private void restoreAnnouncementData() {
		int numLoaded = 0;
		java.sql.Connection con = null;
		PreparedStatement statement = null;
		ResultSet rs = null;
		try {
			con = L2DatabaseFactory.getInstance().getConnection();
			statement = con
					.prepareStatement("SELECT * FROM auto_announcements ORDER BY id");
			rs = statement.executeQuery();
			while (rs.next()) {
				numLoaded++;
				registerGlobalAnnouncement(rs.getInt("id"),
						rs.getString("announcement"), rs.getLong("delay"));
			}
			statement.close();
			_log.info("GameServer: Loaded " + numLoaded
					+ " Auto Announcements.");
		} catch (Exception e) {
		} finally {
			try {
				con.close();
			} catch (Exception e) {
			}
		}
	}

	public void listAutoAnnouncements(L2PcInstance activeChar) {
		NpcHtmlMessage adminReply = new NpcHtmlMessage(5);
		TextBuilder replyMSG = new TextBuilder("<html><body>");
		replyMSG.append("<table width=260><tr>");
		replyMSG.append("<td width=40></td>");
		replyMSG.append("<button value=\"Main\" action=\"bypass -h admin_admin\" width=50 height=15 back=\"sek.cbui94\" fore=\"sek.cbui92\"><br>");
		replyMSG.append("<td width=180><center>Auto Announcement Menu</center></td>");
		replyMSG.append("<td width=40></td>");
		replyMSG.append("</tr></table>");
		replyMSG.append("<br><br>");
		replyMSG.append("<center>Add new auto announcement:</center>");
		replyMSG.append("<center><multiedit var=\"new_autoannouncement\" width=240 height=30></center><br>");
		replyMSG.append("<br><br>");
		replyMSG.append("<center>Delay: <edit var=\"delay\" width=70></center>");
		replyMSG.append("<center>Note: Time in Seconds 60s = 1 min.</center>");
		replyMSG.append("<br><br>");
		replyMSG.append("<center><table><tr><td>");
		replyMSG.append("<button value=\"Add\" action=\"bypass -h admin_add_autoannouncement $delay $new_autoannouncement\" width=60 height=15 back=\"sek.cbui94\" fore=\"sek.cbui92\"></td><td>");
		replyMSG.append("</td></tr></table></center>");
		replyMSG.append("<br>");
		for (AutoAnnouncementInstance announcementInst : AutoAnnouncementHandler
				.getInstance().values()) {
			replyMSG.append("<table width=260><tr><td width=220>["
					+ announcementInst.getDefaultDelay() + "s] "
					+ announcementInst.getDefaultTexts().toString()
					+ "</td><td width=40>");
			replyMSG.append("<button value=\"Delete\" action=\"bypass -h admin_del_autoannouncement "
					+ announcementInst.getDefaultId()
					+ "\" width=60 height=15 back=\"sek.cbui94\" fore=\"sek.cbui92\"></td></tr></table>");
		}
		replyMSG.append("</body></html>");
		adminReply.setHtml(replyMSG.toString());
		activeChar.sendPacket(adminReply);
	}

	public static AutoAnnouncementHandler getInstance() {
		if (_instance == null)
			_instance = new AutoAnnouncementHandler();
		return _instance;
	}

	public int size() {
		return _registeredAnnouncements.size();
	}

	/**
	 * Registers a globally active autoannouncement. <BR>
	 * Returns the associated auto announcement instance.
	 * 
	 * @param String
	 *            announcementTexts
	 * @param int announcementDelay (-1 = default delay)
	 * @return AutoAnnouncementInstance announcementInst
	 */
	public AutoAnnouncementInstance registerGlobalAnnouncement(int id,
			String announcementTexts, long announcementDelay) {
		return registerAnnouncement(id, announcementTexts, announcementDelay);
	}

	/**
	 * Registers a NON globally-active auto announcement <BR>
	 * Returns the associated auto chat instance.
	 * 
	 * @param String
	 *            announcementTexts
	 * @param int announcementDelay (-1 = default delay)
	 * @return AutoAnnouncementInstance announcementInst
	 */
	public AutoAnnouncementInstance registerAnnouncment(int id,
			String announcementTexts, long announcementDelay) {
		return registerAnnouncement(id, announcementTexts, announcementDelay);
	}

	public AutoAnnouncementInstance registerAnnouncment(
			String announcementTexts, long announcementDelay) {
		int nextId = nextAutoAnnouncmentId();
		java.sql.Connection con = null;
		try {
			con = L2DatabaseFactory.getInstance().getConnection();
			PreparedStatement statement = con
					.prepareStatement("INSERT INTO auto_announcements (id,announcement,delay) "
							+ "VALUES (?,?,?)");
			statement.setInt(1, nextId);
			statement.setString(2, announcementTexts);
			statement.setLong(3, announcementDelay);
			statement.executeUpdate();
			statement.close();
		} catch (Exception e) {
			_log.fatal("System: Could Not Insert Auto Announcment into DataBase: Reason: "
					+ "Duplicate Id");
		} finally {
			try {
				con.close();
			} catch (Exception e) {
			}
		}
		return registerAnnouncement(nextId, announcementTexts,
				announcementDelay);
	}

	public int nextAutoAnnouncmentId() {
		int nextId = 0;
		java.sql.Connection con = null;
		PreparedStatement statement = null;
		ResultSet rs = null;
		try {
			con = L2DatabaseFactory.getInstance().getConnection();
			statement = con
					.prepareStatement("SELECT id FROM auto_announcements ORDER BY id");
			rs = statement.executeQuery();
			while (rs.next())
				if (rs.getInt("id") > nextId)
					nextId = rs.getInt("id");
			statement.close();
			nextId++;
		} catch (Exception e) {
		} finally {
			try {
				con.close();
			} catch (Exception e) {
			}
		}
		return nextId;
	}

	private final AutoAnnouncementInstance registerAnnouncement(int id,
			String announcementTexts, long chatDelay) {
		AutoAnnouncementInstance announcementInst = null;
		if (chatDelay < 0)
			chatDelay = DEFAULT_ANNOUNCEMENT_DELAY;
		if (_registeredAnnouncements.containsKey(id))
			announcementInst = _registeredAnnouncements.get(id);
		else
			announcementInst = new AutoAnnouncementInstance(id,
					announcementTexts, chatDelay);
		_registeredAnnouncements.put(id, announcementInst);
		return announcementInst;
	}

	public Collection<AutoAnnouncementInstance> values() {
		return _registeredAnnouncements.values();
	}

	/**
	 * Removes and cancels ALL auto announcement for the given announcement id.
	 * 
	 * @param int Id
	 * @return boolean removedSuccessfully
	 */
	public boolean removeAnnouncement(int id) {
		AutoAnnouncementInstance announcementInst = _registeredAnnouncements
				.get(id);
		java.sql.Connection con = null;
		try {
			con = L2DatabaseFactory.getInstance().getConnection();
			PreparedStatement statement = con
					.prepareStatement("DELETE FROM auto_announcements WHERE id=?");
			statement.setInt(1, announcementInst.getDefaultId());
			statement.executeUpdate();
			statement.close();
		} catch (Exception e) {
			_log.fatal(
					"Could not Delete Auto Announcement in Database, Reason:",
					e);
		} finally {
			try {
				con.close();
			} catch (Exception e) {
			}
		}
		return removeAnnouncement(announcementInst);
	}

	/**
	 * Removes and cancels ALL auto announcement for the given announcement
	 * instance.
	 * 
	 * @param AutoAnnouncementInstance
	 *            announcementInst
	 * @return boolean removedSuccessfully
	 */
	public boolean removeAnnouncement(AutoAnnouncementInstance announcementInst) {
		if (announcementInst == null)
			return false;
		_registeredAnnouncements.remove(announcementInst.getDefaultId());
		announcementInst.setActive(false);
		return true;
	}

	/**
	 * Returns the associated auto announcement instance either by the given
	 * announcement ID or object ID.
	 * 
	 * @param int id
	 * @return AutoAnnouncementInstance announcementInst
	 */
	public AutoAnnouncementInstance getAutoAnnouncementInstance(int id) {
		return _registeredAnnouncements.get(id);
	}

	/**
	 * Sets the active state of all auto announcement instances to that
	 * specified, and cancels the scheduled chat task if necessary.
	 * 
	 * @param boolean isActive
	 */
	public void setAutoAnnouncementActive(boolean isActive) {
		for (AutoAnnouncementInstance announcementInst : _registeredAnnouncements
				.values())
			announcementInst.setActive(isActive);
	}

	/**
	 * Auto Announcement Instance
	 */
	public class AutoAnnouncementInstance {
		private long _defaultDelay = DEFAULT_ANNOUNCEMENT_DELAY;
		private String _defaultTexts;
		private boolean _defaultRandom = false;
		private Integer _defaultId;
		private boolean _isActive;
		public ScheduledFuture<?> _chatTask;

		protected AutoAnnouncementInstance(int id, String announcementTexts,
				long announcementDelay) {
			_defaultId = id;
			_defaultTexts = announcementTexts;
			_defaultDelay = announcementDelay * 1000;
			setActive(true);
		}

		public boolean isActive() {
			return _isActive;
		}

		public boolean isDefaultRandom() {
			return _defaultRandom;
		}

		public long getDefaultDelay() {
			return _defaultDelay;
		}

		public String getDefaultTexts() {
			return _defaultTexts;
		}

		public Integer getDefaultId() {
			return _defaultId;
		}

		public void setDefaultChatDelay(long delayValue) {
			_defaultDelay = delayValue;
		}

		public void setDefaultChatTexts(String textsValue) {
			_defaultTexts = textsValue;
		}

		public void setDefaultRandom(boolean randValue) {
			_defaultRandom = randValue;
		}

		public void setActive(boolean activeValue) {
			if (_isActive == activeValue)
				return;
			_isActive = activeValue;
			if (isActive()) {
				AutoAnnouncementRunner acr = new AutoAnnouncementRunner(
						_defaultId);
				_chatTask = ThreadPoolManager.getInstance()
						.scheduleGeneralAtFixedRate(acr, _defaultDelay,
								_defaultDelay);
			} else
				_chatTask.cancel(false);
		}

		/**
		 * Auto Announcement Runner <BR>
		 * <BR>
		 * Represents the auto announcement scheduled task for each announcement
		 * instance.
		 * 
		 * @author chief
		 */
		private class AutoAnnouncementRunner implements Runnable {
			protected int id;

			protected AutoAnnouncementRunner(int pId) {
				id = pId;
			}

			public synchronized void run() {
				AutoAnnouncementInstance announcementInst = _registeredAnnouncements
						.get(id);
				String text;
				text = announcementInst.getDefaultTexts();
				if (text == null)
					return;
				Announcements.getInstance().announceToAll(text);
			}
		}
	}
}
